if ENEIDA_UTIL_INCLUDE = 'DATA'

align 16

; public data
vm_v4_f32_unit_x dd 1.0,0.0,0.0,0.0
vm_v4_f32_unit_y dd 0.0,1.0,0.0,0.0
vm_v4_f32_unit_z dd 0.0,0.0,1.0,0.0
vm_v4_f32_unit_w dd 0.0,0.0,0.0,1.0
vm_v4_i32_select_x dd 0xffffffff,0,0,0
vm_v4_i32_select_y dd 0,0xffffffff,0,0
vm_v4_i32_select_z dd 0,0,0xffffffff,0
vm_v4_i32_select_w dd 0,0,0,0xffffffff

else if ENEIDA_UTIL_INCLUDE = 'CODE'

;-------------------------------------------------------------------------------
; name: vm_shufps
;
macro vm_shufps dst*,src*,z*, y*, x*, w* {
    shufps dst,src,(z shl 6) or (y shl 4) or (x shl 2) or w
}
;-------------------------------------------------------------------------------
macro vm_s_set dst_r*,s* {
    mov eax,s
    movd dst_r,eax
}
;-------------------------------------------------------------------------------
macro vm_v2_set dst_r*,x*,y* {
    sub rsp,16
    mov dword [rsp],x
    mov dword [rsp+4],y
    movaps dst_r,[rsp]
    add rsp,16
}
;-------------------------------------------------------------------------------
macro vm_v3_set dst_r*,x*,y*,z* {
    sub rsp,16
    mov dword [rsp],x
    mov dword [rsp+4],y
    mov dword [rsp+8],z
    movaps dst_r,[rsp]
    add rsp,16
}
;-------------------------------------------------------------------------------
macro vm_v4_set dst_r*,x*,y*,z*,w* {
    sub rsp,16
    mov dword [rsp],x
    mov dword [rsp+4],y
    mov dword [rsp+8],z
    mov dword [rsp+12],w
    movaps dst_r,[rsp]
    add rsp,16
}
;-------------------------------------------------------------------------------
macro vm_v4_set1 dst_r*,s* {
    mov eax,s
    movd dst_r,eax
    shufps dst_r,dst_r,0x00
}
;-------------------------------------------------------------------------------
; name: vm_v2_dot
; in: vector in xmm0.xy
; in: vector in xmm1.xy
; out: scalar in xmm0.ssss
;
macro vm_v2_dot {
    mulps xmm0,xmm1
    movaps xmm1,xmm0
    shufps xmm0,xmm0,0x00
    shufps xmm1,xmm1,0x55
    addps xmm0,xmm1
}
;-------------------------------------------------------------------------------
; name: vm_v3_dot
; in: vector in xmm0.xyz
; in: vector in xmm1.xyz
; out: scalar in xmm0.ssss
;
macro vm_v3_dot {
    mulps xmm0,xmm1
    movaps xmm1,xmm0
    movaps xmm2,xmm0
    shufps xmm0,xmm0,0x00
    shufps xmm1,xmm1,0x55
    shufps xmm2,xmm2,0xaa
    addps xmm0,xmm1
    addps xmm0,xmm2
}
;-------------------------------------------------------------------------------
; name: vm_v4_dot
; in: vector in xmm0.xyzw
; in: vector in xmm1.xyzw
; out: scalar in xmm0.ssss
;
macro vm_v4_dot {
    mulps xmm0,xmm1
    movaps xmm1,xmm0
    movaps xmm2,xmm0
    movaps xmm3,xmm0
    shufps xmm0,xmm0,0x00
    shufps xmm1,xmm1,0x55
    shufps xmm2,xmm2,0xaa
    shufps xmm3,xmm3,0xff
    addps xmm0,xmm1
    addps xmm2,xmm3
    addps xmm0,xmm2
}
;-------------------------------------------------------------------------------
; name: vm_v2_length
; in: vector in xmm0.xy
; out: scalar in xmm0.ssss
;
macro vm_v2_length {
    mulps xmm0,xmm0
    movaps xmm1,xmm0
    shufps xmm0,xmm0,0x00
    shufps xmm1,xmm1,0x55
    addps xmm0,xmm1
    sqrtps xmm0,xmm0
}
;-------------------------------------------------------------------------------
; name: vm_v3_length
; in: vector in xmm0.xyz
; out: scalar in xmm0.ssss
;
macro vm_v3_length {
    mulps xmm0,xmm0
    movaps xmm1,xmm0
    movaps xmm2,xmm0
    shufps xmm0,xmm0,0x00
    shufps xmm1,xmm1,0x55
    shufps xmm2,xmm2,0xaa
    addps xmm0,xmm1
    addps xmm0,xmm2
    sqrtps xmm0,xmm0
}
;-------------------------------------------------------------------------------
; name: vm_v4_length
; in: vector in xmm0.xyzw
; out: scalar in xmm0.ssss
;
macro vm_v4_length {
    mulps xmm0,xmm0
    movaps xmm1,xmm0
    movaps xmm2,xmm0
    movaps xmm3,xmm0
    shufps xmm0,xmm0,0x00
    shufps xmm1,xmm1,0x55
    shufps xmm2,xmm2,0xaa
    shufps xmm3,xmm3,0xff
    addps xmm0,xmm1
    addps xmm2,xmm3
    addps xmm0,xmm2
    sqrtps xmm0,xmm0
}
;-------------------------------------------------------------------------------
; name: vm_v2_normalize
; in: vector in xmm0.xy
; out: normalized vector in xmm0.xy
;
macro vm_v2_normalize {
    movaps xmm2,xmm0
    mulps xmm0,xmm0
    movaps xmm1,xmm0
    shufps xmm0,xmm0,0x00
    shufps xmm1,xmm1,0x55
    addps xmm0,xmm1
    rsqrtps xmm0,xmm0
    mulps xmm0,xmm2
}
;-------------------------------------------------------------------------------
; name: vm_v3_normalize
; in: vector in xmm0.xyz
; out: normalized vector in xmm0.xyz
;
macro vm_v3_normalize {
    movaps xmm3,xmm0
    mulps xmm0,xmm0
    movaps xmm1,xmm0
    movaps xmm2,xmm0
    shufps xmm0,xmm0,0x00
    shufps xmm1,xmm1,0x55
    shufps xmm2,xmm2,0xaa
    addps xmm0,xmm1
    addps xmm0,xmm2
    rsqrtps xmm0,xmm0
    mulps xmm0,xmm3
}
;-------------------------------------------------------------------------------
; name: vm_v4_normalize
; in: vector in xmm0.xyzw
; out: normalized vector in xmm0.xyzw
;
macro vm_v4_normalize {
    movaps xmm4,xmm0
    mulps xmm0,xmm0
    movaps xmm1,xmm0
    movaps xmm2,xmm0
    movaps xmm3,xmm0
    shufps xmm0,xmm0,0x00
    shufps xmm1,xmm1,0x55
    shufps xmm2,xmm2,0xaa
    shufps xmm3,xmm3,0xff
    addps xmm0,xmm1
    addps xmm2,xmm3
    addps xmm0,xmm2
    rsqrtps xmm0,xmm0
    mulps xmm0,xmm4
}
;-------------------------------------------------------------------------------
; name: vm_v3_cross
; in: vector in xmm0.xyz
; in: vector in xmm1.xyz
; out: vector in xmm0.xyz
;
macro vm_v3_cross {
    movaps xmm2,xmm0
    movaps xmm3,xmm1
    vm_shufps xmm0,xmm0,3,0,2,1
    vm_shufps xmm1,xmm1,3,1,0,2
    vm_shufps xmm2,xmm2,3,1,0,2
    vm_shufps xmm3,xmm3,3,0,2,1
    mulps xmm0,xmm1
    mulps xmm2,xmm3
    subps xmm0,xmm2
}
;-------------------------------------------------------------------------------
; name: vm_m4_zero
;
macro vm_m4_zero dst* {
    xorps xmm0,xmm0
    movaps [dst],xmm0
    movaps [dst+16],xmm0
    movaps [dst+32],xmm0
    movaps [dst+48],xmm0
}
;-------------------------------------------------------------------------------
; name: vm_m4_identity
;
macro vm_m4_identity dst* {
    movaps xmm0,dqword [vm_v4_f32_unit_x]
    movaps xmm1,dqword [vm_v4_f32_unit_y]
    movaps xmm2,dqword [vm_v4_f32_unit_z]
    movaps xmm3,dqword [vm_v4_f32_unit_w]
    movaps [dst],xmm0
    movaps [dst+16],xmm1
    movaps [dst+32],xmm2
    movaps [dst+48],xmm3
}
;-------------------------------------------------------------------------------
; name: vm_m4_translation
; in: translation vector in xmm0.xyz
;
macro vm_m4_translation dst* {
    movaps xmm1,dqword [vm_v4_f32_unit_x]
    movaps xmm2,dqword [vm_v4_f32_unit_y]
    movaps xmm3,dqword [vm_v4_f32_unit_z]
    movaps [dst],xmm1
    movaps [dst+16],xmm2
    movaps [dst+32],xmm3
    movaps [dst+48],xmm0
    movss xmm0,[am_v4_f32_1]
    movss [dst+60],xmm0
}
;-------------------------------------------------------------------------------
; name: vm_m4_scale
; in: scale vector in xmm0.xyz
;
macro vm_m4_scale dst* {
    movaps xmm1,dqword [vm_v4_i32_select_x]
    movaps xmm2,dqword [vm_v4_i32_select_y]
    movaps xmm3,dqword [vm_v4_i32_select_z]
    movaps xmm4,dqword [vm_v4_f32_unit_w]
    andps xmm1,xmm0
    andps xmm2,xmm0
    andps xmm3,xmm0
    movaps [dst+0],xmm1
    movaps [dst+16],xmm2
    movaps [dst+32],xmm3
    movaps [dst+48],xmm4
}
;-------------------------------------------------------------------------------
; name: vm_m4_rotation_x
; in: angle in radians in xmm0.x
;
macro vm_m4_rotation_x dst* {
    am_sincos_ss
    shufps xmm0,xmm0,0x00   ; xmm0.xyzw = sin(rad)
    shufps xmm1,xmm1,0x00   ; xmm1.xyzw = cos(rad)
    xorps xmm2,xmm2
    movaps xmm3,dqword [vm_v4_i32_select_y]
    movaps xmm4,dqword [vm_v4_i32_select_z]
    movaps xmm5,xmm1
    andps xmm5,xmm3
    movaps xmm6,xmm0
    andps xmm6,xmm4
    movaps xmm7,xmm4
    andnps xmm7,xmm5
    orps xmm7,xmm6
    movaps [dst+16],xmm7
    movaps xmm5,xmm2
    subps xmm5,xmm0
    andps xmm5,xmm3
    andps xmm1,xmm4
    andnps xmm4,xmm5
    orps xmm4,xmm1
    movaps [dst+32],xmm4
    movaps xmm0,dqword [vm_v4_f32_unit_x]
    movaps [dst+0],xmm0
    movaps xmm0,dqword [vm_v4_f32_unit_w]
    movaps [dst+48],xmm0
}
;-------------------------------------------------------------------------------
; name: vm_m4_rotation_y
; in: angle in radians in xmm0.x
;
macro vm_m4_rotation_y dst* {
    am_sincos_ss
    shufps xmm0,xmm0,0x00   ; xmm0.xyzw = sin(rad)
    shufps xmm1,xmm1,0x00   ; xmm1.xyzw = cos(rad)
    xorps xmm2,xmm2
    movaps xmm3,dqword [vm_v4_i32_select_x]
    movaps xmm4,dqword [vm_v4_i32_select_z]
    movaps xmm5,xmm1
    andps xmm5,xmm3
    movaps xmm6,xmm2
    subps xmm6,xmm0
    andps xmm6,xmm4
    movaps xmm7,xmm4
    andnps xmm7,xmm5
    orps xmm7,xmm6
    movaps [dst+0],xmm7
    andps xmm0,xmm3
    andps xmm1,xmm4
    andnps xmm4,xmm0
    orps xmm4,xmm1
    movaps [dst+32],xmm4
    movaps xmm0,dqword [vm_v4_f32_unit_y]
    movaps [dst+16],xmm0
    movaps xmm0,dqword [vm_v4_f32_unit_w]
    movaps [dst+48],xmm0
}
;-------------------------------------------------------------------------------
; name: vm_m4_rotation_z
; in: angle in radians in xmm0.x
;
macro vm_m4_rotation_z dst* {
    am_sincos_ss
    shufps xmm0,xmm0,0x00   ; xmm0.xyzw = sin(rad)
    shufps xmm1,xmm1,0x00   ; xmm1.xyzw = cos(rad)
    xorps xmm2,xmm2
    movaps xmm3,dqword [vm_v4_i32_select_x]
    movaps xmm4,dqword [vm_v4_i32_select_y]
    movaps xmm5,xmm1
    andps xmm5,xmm3
    movaps xmm6,xmm0
    andps xmm6,xmm4
    movaps xmm7,xmm4
    andnps xmm7,xmm5
    orps xmm7,xmm6
    movaps [dst+0],xmm7
    movaps xmm6,xmm2
    subps xmm6,xmm0
    andps xmm6,xmm3
    andps xmm1,xmm4
    andnps xmm4,xmm6
    orps xmm4,xmm1
    movaps [dst+16],xmm4
    movaps xmm0,dqword [vm_v4_f32_unit_z]
    movaps [dst+32],xmm0
    movaps xmm0,dqword [vm_v4_f32_unit_w]
    movaps [dst+48],xmm0
}
;-------------------------------------------------------------------------------
; name: vm_m4_lookat
; in: eye position in xmm0.xyz
; in: look at position in xmm1.xyz
; in: up vector in xmm2.xyz
;
macro vm_m4_lookat dst* {
    movaps xmm5,xmm0
    movaps xmm6,xmm1
    movaps xmm0,xmm2
    vm_v3_normalize
    movaps xmm7,xmm0
    movaps xmm0,xmm5
    movaps xmm1,xmm6
    subps xmm0,xmm1
    vm_v3_normalize
    movaps xmm4,xmm0
    movaps xmm0,xmm7
    movaps xmm1,xmm4
    vm_v3_cross
    vm_v3_normalize
    movaps xmm6,xmm0
    movaps xmm0,xmm4
    movaps xmm1,xmm6
    vm_v3_cross
    movaps xmm7,xmm0
    movaps xmm8,xmm4
    ; xmm6 = x_axis, xmm7 = y_axis, xmm8 = z_axis, xmm5 = eye_pos
    movaps [dst+0],xmm6
    movaps [dst+16],xmm7
    movaps [dst+32],xmm8
    movaps xmm0,dqword [vm_v4_f32_unit_w]
    movaps [dst+48],xmm0
    vm_m4_transpose dst,dst
    movaps xmm0,xmm5
    movaps xmm1,xmm6
    vm_v3_dot
    xorps xmm3,xmm3
    subps xmm3,xmm0
    movss [dst+48],xmm3
    movaps xmm0,xmm5
    movaps xmm1,xmm7
    vm_v3_dot
    xorps xmm3,xmm3
    subps xmm3,xmm0
    movss [dst+52],xmm3
    movaps xmm0,xmm5
    movaps xmm1,xmm8
    vm_v3_dot
    xorps xmm3,xmm3
    subps xmm3,xmm0
    movss [dst+56],xmm3
}
;-------------------------------------------------------------------------------
; name: vm_m4_perspective
; in: fovy in xmm0.x
; in: aspect in xmm1.x
; in: znear in xmm2.x
; in: zfar in xmm3.x
;
macro vm_m4_perspective dst* {
    ; save parameters
    movss xmm8,xmm1     ; aspect
    movss xmm9,xmm2     ; znear
    movss xmm10,xmm3    ; zfar
    movss xmm1,[am_v4_f32_0p5]
    mulss xmm0,xmm1     ; 0.5 * fovy
    movss xmm1,[am_v4_f32_0p5pi]
    subss xmm1,xmm0
    movss xmm0,xmm1
    am_tan_ss
    xorps xmm7,xmm7     ; zero vector
    movss xmm6,xmm9
    subss xmm6,xmm10
    rcpss xmm6,xmm6     ; 1.0 / (znear - zfar)
    ; col 0
    movaps [dst+0],xmm7
    movss xmm1,xmm0
    divss xmm1,xmm8
    movss [dst+0],xmm1
    ; col 1
    movaps [dst+16],xmm7
    movss [dst+20],xmm0
    ; col 2
    movaps [dst+32],xmm7
    movss xmm0,xmm9
    addss xmm0,xmm10
    mulss xmm0,xmm6
    movss [dst+40],xmm0
    movss xmm0,[am_v4_f32_m1]
    movss [dst+44],xmm0
    ; col 3
    movaps [dst+48],xmm7
    movss xmm0,xmm9
    mulss xmm0,xmm10
    addss xmm0,xmm0
    mulss xmm0,xmm6
    movss [dst+56],xmm0
}
;-------------------------------------------------------------------------------
; name: vm_m4_transpose
;
macro vm_m4_transpose dst*,src* {
    movaps xmm0,[src+0]
    unpcklps xmm0,[src+32]
    movaps xmm1,[src+16]
    unpcklps xmm1,[src+48]
    movaps xmm2,[src+0]
    unpckhps xmm2,[src+32]
    movaps xmm3,[src+16]
    unpckhps xmm3,[src+48]
    movaps xmm4,xmm0
    unpcklps xmm4,xmm1
    unpckhps xmm0,xmm1
    movaps [dst+0],xmm4
    movaps [dst+16],xmm0
    movaps xmm4,xmm2
    unpcklps xmm4,xmm3
    unpckhps xmm2,xmm3
    movaps [dst+32],xmm4
    movaps [dst+48],xmm2
}
;-------------------------------------------------------------------------------
; name: vm_m4_copy
;
macro vm_m4_copy dst*,src* {
    movaps xmm0,[src+0]
    movaps xmm1,[src+16]
    movaps xmm2,[src+32]
    movaps xmm3,[src+48]
    movaps [dst+0],xmm0
    movaps [dst+16],xmm1
    movaps [dst+32],xmm2
    movaps [dst+48],xmm3
}
;-------------------------------------------------------------------------------
; name: vm_m4_mul_v4
; in: vector in xmm0.xyzw
; in: pointer to the transformation matrix in m
; out: vector in xmm0.xyzw
;
macro vm_m4_mul_v4 m* {
    movaps xmm1,xmm0
    movaps xmm2,xmm0
    movaps xmm3,xmm0
    shufps xmm0,xmm0,0x00
    shufps xmm1,xmm1,0x55
    shufps xmm2,xmm2,0xaa
    shufps xmm3,xmm3,0xff
    mulps xmm0,[m+0]
    mulps xmm1,[m+16]
    mulps xmm2,[m+32]
    mulps xmm3,[m+48]
    addps xmm0,xmm1
    addps xmm2,xmm3
    addps xmm0,xmm2
}
;-------------------------------------------------------------------------------
; name: vm_m4_mul_m4
;
macro vm_m4_mul_m4 dst*,m0*,m1* {
    movaps xmm4,[m0+0]
    movaps xmm5,[m0+16]
    movaps xmm6,[m0+32]
    movaps xmm7,[m0+48]
    ; col 0
    movaps xmm0,[m1+0]
    movaps xmm1,xmm0
    movaps xmm2,xmm0
    movaps xmm3,xmm0
    shufps xmm0,xmm0,0x00
    shufps xmm1,xmm1,0x55
    shufps xmm2,xmm2,0xaa
    shufps xmm3,xmm3,0xff
    mulps xmm0,xmm4
    mulps xmm1,xmm5
    mulps xmm2,xmm6
    mulps xmm3,xmm7
    addps xmm0,xmm1
    addps xmm2,xmm3
    addps xmm0,xmm2
    movaps [dst+0],xmm0
    ; col 1
    movaps xmm0,[m1+16]
    movaps xmm1,xmm0
    movaps xmm2,xmm0
    movaps xmm3,xmm0
    shufps xmm0,xmm0,0x00
    shufps xmm1,xmm1,0x55
    shufps xmm2,xmm2,0xaa
    shufps xmm3,xmm3,0xff
    mulps xmm0,xmm4
    mulps xmm1,xmm5
    mulps xmm2,xmm6
    mulps xmm3,xmm7
    addps xmm0,xmm1
    addps xmm2,xmm3
    addps xmm0,xmm2
    movaps [dst+16],xmm0
    ; col 2
    movaps xmm0,[m1+32]
    movaps xmm1,xmm0
    movaps xmm2,xmm0
    movaps xmm3,xmm0
    shufps xmm0,xmm0,0x00
    shufps xmm1,xmm1,0x55
    shufps xmm2,xmm2,0xaa
    shufps xmm3,xmm3,0xff
    mulps xmm0,xmm4
    mulps xmm1,xmm5
    mulps xmm2,xmm6
    mulps xmm3,xmm7
    addps xmm0,xmm1
    addps xmm2,xmm3
    addps xmm0,xmm2
    movaps [dst+32],xmm0
    ; col 3
    movaps xmm0,[m1+48]
    movaps xmm1,xmm0
    movaps xmm2,xmm0
    movaps xmm3,xmm0
    shufps xmm0,xmm0,0x00
    shufps xmm1,xmm1,0x55
    shufps xmm2,xmm2,0xaa
    shufps xmm3,xmm3,0xff
    mulps xmm0,xmm4
    mulps xmm1,xmm5
    mulps xmm2,xmm6
    mulps xmm3,xmm7
    addps xmm0,xmm1
    addps xmm2,xmm3
    addps xmm0,xmm2
    movaps [dst+48],xmm0
}
;-------------------------------------------------------------------------------

end if
